今天要來開發圖片上傳的API,我們在使用者個人資料和文章封面都會使用到這支API的功能。
首先想先來探討,圖片上傳的存放位置要放在哪比較好,
圖片可以存放到伺服器端,也可以存放到資料庫,接下來先來分兩者的優缺點
✔️優點:
❌缺點:
✔️優點:
❌缺點:
綜合以上分析,因為我們的系統需要頻繁讀取和使用圖片,而且這些圖片的大小相對較大,所以我們選擇存放在伺服器
。
首先先安裝我們此次要用到的套件multer
npm install multer
接著在專案下建立uploads
這個資料夾,用來存放上傳的圖片
到config
資料夾底下default.json
新增 "fileMaxSize": "2000000"
{
"mongoURI": <資料庫連結>,
"jwtSecret": "secrettoken",
"fileMaxSize": "2000000"
}
在controllers
資料夾底下新增images-controller.js
//image-controller.js
const HttpError = require('../models/http-error');
const config = require('config');
//圖片上傳
exports.uploadImage = (req, res, next) => {
if (!req.file) {
const error = new HttpError('沒有檔案被上傳', 400);
return next(error);
}
const imageUrl = `http://localhost:5000/uploads/${req.file.filename}`;
res.json({ success: true, data: { url: imageUrl } });
};
//圖片檔案格式和大小判斷
exports.uploadErrorHandler = (err, req, res, next) => {
if (err.code === "LIMIT_FILE_TYPES") {
res.status(422).json({ error: "只支援jpg、jpeg、png" });
return;
}
if (err.code === "LIMIT_FILE_SIZE") {
res.status(422).json({ error: `檔案過大,最大為 ${config.get('fileMaxSize')} / 1000000}MB` });
return;
}
next(err);
};
在routes
資料夾底下新增image-routes.js
//image-routes.js
const express = require('express');
const multer = require('multer'); //引入安裝的套件
const path = require('path');
const auth = require('../../middleware/auth');
const router = express.Router();
const imageControllers = require("../../controllers/images-controller");
const config = require('config');
//判斷檔案類型是否支援
const fileFilter = (req, file, cb) => {
const allowedTypes = ["image/jpeg", "image/jpg", "image/png"];
if (!allowedTypes.includes(file.mimetype)) {
const error = new Error("不支援的檔案類型(只支援jpg、jpeg、png)");
error.code = "LIMIT_FILE_TYPES";
return cb(error, false);
}
cb(null, true);
};
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/') // This directory should exist in your server root.
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname)); // Append the date to prevent overwriting.
}
});
// Multer setup
const upload = multer({
storage: storage,
fileFilter: fileFilter,
limits:{
fileSize: config.get("fileMaxSize")
}
});
router.post('/upload', auth, upload.single('image'), imageControllers.uploadImage, imageControllers.uploadErrorHandler);
module.exports = router;
最後到server.js
裡面引入image routes,並設定express
//server.js
const express = require('express');
const connectDB = require('./config/db');
const app = express();
const bodyParser = require('body-parser');
const users = require('./routes/api/users-route');
const auth = require('./routes/api/auth-route');
const posts = require('./routes/api/posts-route');
const images = require('./routes/api/images-route');
connectDB();
app.use(bodyParser.json());
/**
* 告訴 Express 提供在 uploads 目錄中的靜態檔案
* 當瀏覽器或任何客戶端向 /uploads 發起請求時,它實際上是在請求伺服器的 uploads 目錄中的檔案。
**/
app.use('/uploads', express.static('uploads'));
(略...)
app.use('/api/users', users);
app.use('/api/auth', auth);
app.use('/api/posts', posts);
app.use('/api/images', images);
圖片上傳
⚠️這邊有一個我在開發時踩到的坑,當時我都是使用網頁版的postman
在進行測試,但當我要來網頁版的postman測試圖片上傳時會一直出現選不到檔案的問題,查了一下原來要使用桌面版的postman
才可以正常抓取電腦上的檔案
- 關於此議題更詳細的解釋